あたらしいフロントエンド開発ツール「Nue」
About Nue
鵺(ぬえ)。
猿の顔、タヌキの体、蛇の尻尾、虎の脚を持つ妖怪です。
日本人ならNueと聞いた場合、思い浮かべるのは↑かと思うのですが、
これは先日リリースされた、フロントエンド開発ツールセットです。
*「Nue」はドイツ語で、「新しい」という意味だそうな
*「Nue」はドイツ語の「neu」に由来しており、英語で「新しい」という意味だそうな
開発者はTero Piirainenという方で、
現在彼1人で開発しています。
ここを見ると、「Webの開発方法が変わるかも」と
かなりすごいことが書いてありますが、どんなものなのか見ていきましょう。
Nueとはなんなのか?
公式を見ると、↓のようなことを言っています。
- React、Vue、Next.js、Vite、Astroの代わりになる
- NueはSPAMPAの両方に対するサポートを備えたWebアプリケーションビルダーである
- Nueは最終的に完全なフロントエンド開発ツールセットとなる。目標は2024年3月
最終的にここにあるライブラリ・ツールがすべて実装されて
Nue Toolsの完成となります。
これが完成したとき、Nueは完全なフロントエンド開発ツールセットとなり、
Vite、Next.js、Astroなどをリプレイスする手段となるとのこと。
これがNueの最終目標であり、2024年3月を目処に開発しているようです。
Nue JS
今回リリースされたライブラリはNue JSで、
これはUIを構築するためのJavaScriptライブラリです。
React、Vue、Svelteの代替として使うことができ、
HTML、CSS、JavaScriptの基本がわかれば使えます。
その他Nue
Nue Js以外の、Nue css、SPAを構築するためのNue MVC、
UI開発のための再利用可能なコンポーネントであるNue UI、
MDX、MDCの代わりとなるNuemark、
NextやNuxt、Astroの代替となるNuekitなどについては
今後順次リリースしていく予定のようです。
Bun + Nue
現状、NueはNodeかbunで動作しますが、Bunがおすすめみたいです。
今回はBunをつかってNueのサンプルをうごかしてみましょう。
Environment
今回試した環境は以下のとおりです。
- MacBook Pro (13-inch, M1, 2020)
- OS : MacOS 13.5.2
- Bun : 1.0.2
Try Nue.js
まずはbunをインストールまたはupgradeしましょう。
% curl -fsSL https://bun.sh/install | bash or % bun upgrade ・・・ % bun --version 1.0.2
Nueを動かす方法は2つ紹介されています。
簡単なのはリポジトリをcloneする方法で、↓のようにすればすぐ動作確認できます。
# clone the repository git clone https://github.com/nuejs/create-nue.git # cd to your newly created app cd create-nue # install dependencies npm install # Build demo site and start a HTTP server npm run start # Open the demo on the browser open "http://localhost:8080"
今回は↑のコードを参考に、最小のサンプルをつくって確認してみましょう。
適当なディレクトリをつくってpackage.jsonを作成します。
% mkdir hello-nue && cd hello-nue % mkdir www % npm init % npm install nuejs-core js-yaml --save
package.jsonの中身はこんな感じです。
{ "name": "hello-nue", "version": "1.0.0", "type": "module", "scripts": { "serve": "cd www && ../scripts/server.js", "compile": "./scripts/compile.js", "render": "./scripts/render.js" }, "author": "", "license": "ISC", "dependencies": { "js-yaml": "^4.1.0", "nuejs-core": "^0.1.1" } }
ES Module方式にするのと、
コンパイル・レンダリング・サーバ起動用のスクリプトを記述します。
Componentの作成
Nueコンポーネントは再利用可能なUIパーツです。
src/foo.nueファイルを作成しましょう。
<div @name="foo-div" class="{ type }"> <img src="{ img }" height="{img_height}" width="{img_width}"> <aside> <h3>{ title }</h3> <p>{ desc }</p> </aside> </div>
コンポーネントは、@nameで指定された名前を持つHTMLのフラグメントです。
ファイルには任意の拡張子が使えますが「.nue」拡張子が推奨とのこと。
次に.nueをコンパイルするファイル(scripts/compile.js)を作成します。
このファイルはnuejs-coreモジュールを使ってさきほどのnueファイルをjsにコンパイルして
公開用ディレクトリに出力します。
#!/usr/bin/env node import { compileFile } from 'nuejs-core' const target_js = 'www/foo.js' // compile nue source code for browser execution await compileFile('src/foo.nue', target_js) console.info('compiled', target_js)
次はレンダリング用ファイルを作成します。
サーバーコンポーネントはrenderor/renderFile関数でレンダリングし、
reactiveコンポーネントはmountをつかってレンダリングするとのことです。
※参考:https://nuejs.org/docs/nuejs/component-basics.html
#!/usr/bin/env node import { parse, render } from 'nuejs-core' import { promises as fs } from 'node:fs' // read() function for reading assets const read = async (name, dir='src') => await fs.readFile(dir + '/' + name, 'utf-8') // define a component const component = await read('foo.nue'); // render the component with some data const html = '<!DOCTYPE html>\n\n' + render(component, { title: '鵺サンプル', desc: 'Hello 鵺!', img: '<鵺画像のパス>', img_width:"20%", img_height:"20%", type: 'banner', }); // write index.html await fs.writeFile('./www/index.html', html) console.log('wrote', 'www/index.html')
ここまでできたらcompileとrenderをbunで実行します。
% bun compile compiled www/foo.js % bun render $ ./scripts/render.js wrote www/index.html
これでfoo.jsとindex.htmlが生成されました。
最後にscripts/serve.jsを作成して、
htmlサーバを起動します。 (create-nueほぼそのまま)
#!/usr/bin/env node // a super minimal web server to serve files on the current working directory import { join, extname } from 'node:path' import http from 'node:http' import fs from 'node:fs' const TYPES = { html: 'text/html; charset=UTF-8', js: 'application/javascript', svg: 'image/svg+xml', ico: 'image/x-icon', png: 'image/png', jpg: 'image/jpg', css: 'text/css' } const PORT = 8080 http.createServer(async (req, res) => { let { url } = req // favicon.icoのリクエストを無効化。 // これがないとエラーになってた if (url === '/favicon.ico') { res.writeHead(204, { 'Content-Type': 'image/x-icon' }); res.end(); return; } if (url.endsWith('/')) url += 'index.html' const path = join('.', url) const ext = extname(path).slice(1) const head = { 'Content-Type': TYPES[ext] } try { res.writeHead(200, head) fs.createReadStream(path).pipe(res) } catch(e) { res.writeHead(404, head) res.end('') } }).listen(PORT) console.log(process.isBun ? 'Bun' : 'Node', `HTTP server at http://localhost:${PORT}/`)
bun serveでHTTPサーバを起動してブラウザでアクセスしてみましょう。
% bun serve $ cd www && ../scripts/server.js Node HTTP server at http://localhost:8080/
nueで作成したHTMLが表示されました。
Summary
今回はとりあえずNue Jsでシンプルなコンポーネントを
ビルドして表示してみました。
いちいち手動で面倒だったのですが、今後このあたりも洗練されていくかとおもいます。